home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 25 / Mac Magazin and MacEasy Magazine CD - Issue 25.iso / Grafik & Text / Alpha / Tcl / SystemCode / fill.tcl < prev    next >
Text File  |  1996-08-15  |  12KB  |  402 lines

  1. ####################################################################
  2. # Much by Vince Darley.
  3. #                                    created: 3/7/95 {7:49:47 pm} 
  4. #                                last update: 16/5/96 
  5. #  Author: Vince Darley
  6. #  E-mail: <mailto:vince@das.harvard.edu>
  7. #    mail: Division of Applied Sciences, Harvard University
  8. #          Oxford Street, Cambridge MA 02138, USA
  9. #     www: <http://www.fas.harvard.edu/~darley/>
  10. #  
  11. ####################################################################
  12.  
  13. ## 
  14.  # Here's a    brief explanation of the smart fillParagraph routines
  15.  # 
  16.  # 'fillParagraph'
  17.  #       If there's a    selection, then    fill all paragraphs    in that
  18.  #       selection. If not then fill the paragraph surrounding the
  19.  #       insertion point.    The    definition of a    'paragraph'    may    be
  20.  #       mode    dependent (see paraStart, paraFinish)
  21.  #       
  22.  # 'fillOneParagraph'
  23.  #       Fills the single    paragraph surrounding the insertion    point.
  24.  #       If called with parameter    '0', it    doesn't    bother to remember
  25.  #       where the insertion point was, which    makes multiple paragraph
  26.  #       fills quicker when called by    'fillParagraph'
  27.  #       
  28.  # 'rememberWhereYouAre'
  29.  #       Given the start of a    paragraph and the point    to remember,
  30.  #       this    creates    a record stored    in '__g_remember_pos' so that
  31.  #       the following function can find that    spot later,    even after
  32.  #       the paragraph has had space/tabs/new-lines meddled with.
  33.  #       
  34.  # 'goBackToWhereYouWere'
  35.  #       Given the beginning and end of a    selection, where the beginning
  36.  #       corresponds to a    previous call of 'rememberWhereYouAre',    this
  37.  #       procedure will move the insertion point to the correct place.
  38.  #       
  39.  # 'texParaCommands'
  40.  #       A variable containing the bulk of a regexp for paragraph
  41.  #       indicators in 'TeX' mode.
  42.  #       
  43.  # 'paraStart'
  44.  #       Finds the start of the paragraph    containing the insertion point.
  45.  #       
  46.  # 'paraFinish'
  47.  #       Finds the end of    the    paragraph containing the insertion point.
  48.  ##
  49.     
  50. proc fillParagraph {} {
  51.     if {[getPos] == [selEnd]} {
  52.         fillOneParagraph
  53.     } else {    
  54.         set start [getPos]
  55.         set end [selEnd]
  56.         set p $start
  57.         while { $p < $end && $p < [maxPos]} {
  58.             goto $p
  59.             set p [fillOneParagraph 0]
  60.         }
  61.         goto $start
  62.     }
  63. }
  64.  
  65. proc rememberWhereYouAre { startPara pos } {
  66.     global __g_remember_str
  67.     set srem [expr $pos -20 < $startPara ? $startPara : $pos - 20]
  68.     set __g_remember_str [quoteExpr2 [getText $srem $pos ] ]
  69.     regsub -all "\[ \t\r\]+" $__g_remember_str {[ \t\r]+} __g_remember_str
  70. }
  71.  
  72. proc goBackToWhereYouWere { start end } {
  73.     global __g_remember_str
  74.     if { $__g_remember_str != "" } {
  75.         regexp -indices ".*(${__g_remember_str}).*" [getText $start $end] wholematch submatch
  76.         goto [expr $start + 1 + [lindex $submatch 1]]
  77.     } else {
  78.         goto $start
  79.     }
  80. }
  81.  
  82. ## 
  83.  # -------------------------------------------------------------------------
  84.  #     
  85.  #    "getLeadingIndent" --
  86.  #    
  87.  #     Find the indentation of the line containing 'pos',    and    convert    it
  88.  #     to    a minimal form of tabs followed    by spaces.    If 'size'
  89.  #     is    given, then    the    variable of    that name is set to    the    length of
  90.  #     the indent. Similarly 'halftab' can be set to half a tab.
  91.  # -------------------------------------------------------------------------
  92.  ##
  93. proc getLeadingIndent { pos {size ""} {halftab ""} } {
  94.     # get the leading whitespace of the current line
  95.     set res [search -s -n -f 1 -r 1 "^\[ \t\]*" [lineStart $pos]]
  96.     
  97.     # convert it to minimal form: tabs then spaces, stored in 'front'
  98.     getWinInfo a
  99.     set sp [string range "              " 1 $a(tabsize) ]
  100.     regsub -all $sp [eval getText $res] "\t" front
  101.     regsub -all "\[ \]+\t" $front "\t" front
  102.     if { $size != "" } {
  103.         upvar $size ind
  104.         # get the length of the indent
  105.         regsub -all "\t" $front $sp lfront
  106.         set ind [string length $lfront]
  107.     }
  108.  
  109.     if { $halftab != "" } {
  110.         upvar $halftab ht
  111.         # get the length of half a tab
  112.         set ht [string range "            " 1 [expr $a(tabsize)/2]]
  113.     }
  114.     
  115.     return $front
  116. }
  117.  
  118. proc fillOneParagraph { {remember 1} } {
  119.     global leftFillColumn fillColumn doubleSpaces
  120.  
  121.     set pos [getPos]
  122.     
  123.     set start [paraStart $pos] 
  124.     set end [paraFinish $pos]
  125.     if $remember { rememberWhereYouAre $start $pos }
  126.  
  127.     # Get the leading whitespace of the current line and store length in 'left'
  128.     set front [getLeadingIndent $pos left]
  129.     # fill the text
  130.     regsub -all "\[ \t\r\]+" [string trim [getText $start $end]] " " text
  131.     # turn single spaces at end of sentences into double
  132.     if {$doubleSpaces} {regsub -all {(([^A-Z@]|\\@)[.?!]("|'|'')?([])])?) } $text {\1  } text}
  133. #     if {$doubleSpaces} {regsub -all {(([^A-Z@]|\\@)[.?!][])'"]?) } $text {\1  } text}
  134.  
  135.     # temporarily adjust the fillColumns
  136.     set ol $leftFillColumn
  137.     set or $fillColumn
  138.     set leftFillColumn 0
  139.     set fillColumn [expr $fillColumn - $left]
  140.         
  141.     # break and indent the paragraph
  142.     regsub -all "\r" "\r[string trimright [breakIntoLines $text]]" "\r${front}" text
  143.     
  144.     # don't replace if nothing's changed
  145.     if { "$text\r" != "\r[getText $start $end]" } {
  146.         replaceText $start $end "[string range "$text" 1 end]\r"
  147.         if $remember { goBackToWhereYouWere $start [expr $start + [string length $text]] }
  148.     }
  149.     
  150.     set leftFillColumn $ol
  151.     set fillColumn  $or
  152.     # in case we wish to fill a region
  153.     return $end
  154. }
  155.  
  156.  
  157. ## 
  158.  # -------------------------------------------------------------------------
  159.  # 
  160.  #    "paraStart"    -- "paraFinish"
  161.  # 
  162.  #     Newly simplified version with fewer regexp    '()' pairs.    Also I think
  163.  #     it    deals better with TeX comments than    the    old    regexp.
  164.  #     
  165.  #     "Start": It's pretty clear    for    non    TeX    modes how this works.  The only    
  166.  #     key is    that we    start at the beginning of the current line and look    back.  
  167.  #     We    then have a    quick check    for    whether    we found that very beginning (in 
  168.  #     which case    return it) or if not (in which case we have found the end of 
  169.  #     the previous paragraph) we move forward a line.
  170.  # 
  171.  #     "Finish": The only    addition is    the    need for an    additional check for
  172.  #     stuff which explicitly    ends lines.
  173.  #       
  174.  #    Results:
  175.  #     The start/finish position of the paragraph containing the given 'pos'
  176.  # 
  177.  # --Version--Author------------------Changes-------------------------------
  178.  #      1.1      <vince@das.harvard.edu> Cut down on '()' pairs
  179.  #    1.2     Vince - March '96          Better filling for TeX tables ('hline')
  180.  #    1.3     Johan Linde - May '96   Now sensitive to HTML elements
  181.  # -------------------------------------------------------------------------
  182.  ##
  183. proc paraStart {pos} {
  184.     global mode texParaCommands htmlParaCommands
  185.     if {$pos == [maxPos]} {incr pos -1}
  186.     set pos [lineStart $pos]
  187.     if { $mode == "TeX" || $mode == "Bib" } {
  188.         set startPara {^[ \t]*$|\\\\[ \t]*$|%.*$|\\h+line[ \t]*$|\$\$[ \t]*$|^[ \t]*(\\(}
  189.         append startPara $texParaCommands {)(\[.*\]|\{.*\}|•)*[ \t]*)+$}
  190.     } elseif {$mode == "HTML"} {
  191.         set startPara {^[ \t]*$|</?(}
  192.         append startPara $htmlParaCommands {)([ \t\r]+[^>]*>|>)}
  193.     } else {
  194.         set startPara {^([ \t]*|([\\%].*))$}
  195.     }
  196.     set res [search -s -n -f 0 -r 1 -l 0 "$startPara" $pos]
  197.     if {![string length $res] || $res == "0 0" } {return 0}
  198.     if { [lindex $res 0] == $pos } {
  199.         return $pos
  200.     } else {
  201.         return [nextLineStart [lindex $res 0]]
  202.     }
  203.     
  204. }
  205.  
  206. set texParaCommands {\[|\]|begin|end|(protect\\)?label|(sub)*section|subfigure|paragraph|centerline|centering|caption|chapter|item|bibitem|intertext}
  207. set htmlParaCommands {html|head|title|body|h[1-6]|p|div|blockquote|center|address|pre}
  208. append htmlParaCommands {|br|hr|wbr|basefont|ul|ol|li|dir|menu|dl|dd|dt|form|input}
  209. append htmlParaCommands {|select|option|textarea|caption|table|tr|frameset|frame|noframes}
  210. append htmlParaCommands {|map|area|applet|param|script|base|link|meta|isindex}
  211.  
  212. proc paraFinish {pos} {
  213.     global mode texParaCommands htmlParaCommands
  214.     set pos [lineStart $pos]
  215.     set end [maxPos]
  216.     if { $mode == "TeX" || $mode == "Bib" } {
  217.         set endPara {^[ \t]*$|\$\$[ \t]*$|^[ \t]*(\\(}
  218.         append endPara $texParaCommands {)(\[.*\]|\{.*\}|•)*[ \t]*)+$}
  219.     } elseif {$mode == "HTML"} {
  220.         set endPara {^[ \t]*$|</?(}
  221.         append endPara $htmlParaCommands {)([ \t\r]+[^>]*>|>)}
  222.     } else {
  223.         set endPara {^([ \t]*|([\\%].*))$}
  224.     }
  225.     
  226.     set res [search -s -n -f 1 -r 1 -l $end "$endPara" $pos]
  227.     if {![string length $res]} {return $end}
  228.     set cpos [lineStart [lindex $res 0] ]
  229.     if { $cpos == $pos } {
  230.         return [nextLineStart $cpos]
  231.     }
  232.     # A line which ends in '\\', '%...', '\hline', '\hhline'
  233.     # signifies the end of the current paragraph in TeX mode
  234.     # (the above checked for beginning of the next paragraph).
  235.     if { $mode == "TeX" || $mode == "Bib" } {
  236.         set res2 [search -s -n -f 1 -r 1 -l $end {((\\\\|\\h+line)[ \t]*|%.*)$} $pos]
  237.         if [string length $res2] {
  238.             if { [lindex $res2 0] < $cpos } {
  239.                 return [nextLineStart [lindex $res2 0]]
  240.             }
  241.         }
  242.     }
  243.  
  244.     return $cpos
  245.     
  246. }
  247.  
  248.  
  249. proc sentenceParagraph {} {
  250.     set pos [getPos]
  251.     set start [paraStart $pos] 
  252.     set finish [paraFinish $pos]
  253.  
  254.     set t [string trim [getText $start $finish]]
  255.     set period [regexp {\.$} $t]
  256.     regsub -all "\[ \t\r\]+" $t " " text
  257.     regsub -all {\. } $text "Δ" text
  258.     set result ""
  259.     foreach line [split [string trimright $text {.}] "Δ"] {
  260.         if {[string length $line]} {
  261.             append result [breakIntoLines $line] ".\r"
  262.         }
  263.     }
  264.     if {!$period && [regexp {\.\r} $result]} {
  265.         set result [string trimright $result ".\r"]
  266.         append result "\r"
  267.     }
  268.     if {$result != [getText $start $finish]} {
  269.         replaceText $start $finish $result
  270.     }
  271.     goto $pos
  272. }
  273.  
  274. proc getEndpts {} {
  275.     if {[getPos] == [selEnd]} {
  276.         set start [getPos]
  277.         set finish [getMark]
  278.         if {$start > $finish} {
  279.             set temp $start
  280.             set start $finish
  281.             set finish $temp
  282.         }
  283.     } else {
  284.         set start [getPos]
  285.         set finish [selEnd]
  286.     }
  287.     return [list $start $finish]
  288. }
  289.  
  290.  
  291. proc fillRegion {} {
  292.     global leftFillColumn
  293.     set ends [getEndpts]
  294.     set start [lineStart [lindex $ends 0]]
  295.     set finish [lindex $ends 1]
  296.     goto $start
  297.     set text [fillText $start $finish]
  298.     replaceText $start $finish [format "%$leftFillColumn\s" ""] $text "\r"
  299. }
  300.     
  301. proc wrapParagraph {} {
  302.     set pos [getPos]
  303.     set start [paraStart $pos] 
  304.     set finish [paraFinish $pos]
  305.     goto $start
  306.     wrapText $start $finish
  307.     goto $pos
  308. }
  309.  
  310. proc wrapRegion {} {
  311.     set ends [getEndpts]
  312.     set start [lineStart [lindex $ends 0]]
  313.     set finish [lindex $ends 1]
  314.     if {$start == $finish} {
  315.         set finish [maxPos]
  316.     }
  317.     wrapText $start $finish
  318. }
  319.     
  320.  
  321.  
  322. # Remove text from window, transform, and insert back into window.
  323. proc fillText {from to} {
  324.     global doubleSpaces
  325.     set text [getText $from $to]
  326.     regexp {^ *} $text front
  327.     set text [string trim $text]
  328.     regsub -all "\[ \t\r\]+" $text " " text
  329.     if {$doubleSpaces} {regsub -all {(\.|\?|\!) } $text {\1  } text}
  330.     regsub -all "\r" [string trimright [breakIntoLines $text]] "\r${front}" text
  331.     return $front$text
  332. }
  333.  
  334. proc paragraphToLine {} {
  335.     global fillColumn
  336.     global leftFillColumn
  337.     set fc $fillColumn
  338.     set lc $leftFillColumn
  339.     set fillColumn 10000
  340.     set leftFillColumn 0
  341.     fillRegion
  342.     set fillColumn $fc
  343.     set leftFillColumn $lc
  344. }
  345.  
  346. proc lineToParagraph {} {
  347.     global fillColumn
  348.     global leftFillColumn
  349.     set fc $fillColumn
  350.     set fillColumn 75
  351.     set lc $leftFillColumn
  352.     set leftFillColumn 0
  353.     fillRegion
  354.     set fillColumn $fc
  355.     set leftFillColumn $lc
  356. }
  357.  
  358.  
  359. #set sentEnd {[.!?](\r| +)}
  360. set sentEnd {(\r\r|[.!?](\r| +))}
  361. set sentBeg {[\r ][A-Z]}
  362.  
  363. proc nextSentence {} {
  364.     global sentBeg sentEnd
  365.     if {![catch {search -s -f 1 -r 1 $sentEnd [getPos]} mtch]} {
  366.         if {![catch {search -s -f 1 -r 1 -i 0 $sentBeg [expr [lindex $mtch 1]-1]} mtch]} {
  367.             goto [expr [lindex $mtch 0]+1]
  368.         }
  369.     }
  370. }
  371.  
  372.  
  373. proc prevSentence {} {
  374.     global sentBeg sentEnd
  375.     if {[catch {search -s -f 0 -r 1 $sentBeg [expr [getPos]-2]} mtch]} return
  376.     if {![catch {search -s -f 0 -r 1 $sentEnd [lindex $mtch 1]} mtch]} {
  377.         if {![catch {search -s -f 1 -r 1 -i 0 $sentBeg [expr [lindex $mtch 1]-1]} mtch]} {
  378.             goto [expr [lindex $mtch 0]+1]
  379.         }
  380.     }
  381. }
  382. # 5 730 845 955
  383.  
  384. #===============================================================================
  385. # Called by Alpha to do "soft wrapping"
  386. proc softProc {pos start next} {
  387.     global leftFillColumn
  388.     goto $start
  389.     set finish [paraFinish $start]
  390.     set text [fillText $start $finish]
  391.     if {"${text}\r" != [getText $start $finish]} {
  392.         replaceText $start $finish [format "%$leftFillColumn\s" ""] $text "\r"
  393.         return 1
  394.     } else {
  395.         return 0
  396.     }
  397. }
  398.  
  399.  
  400.